#!/usr/bin/env python3
# -*- coding: utf-8 -*-

from functools import wraps
from selenium import webdriver
import unittest
import time
import HTMLTestReport, HTMLTestRunner


class Screen(object):

    def __init__(self, driver):
        self.driver = driver

    def __call__(self, func):
        # 不用wraps获取的case名称是被装饰函数"wrapper"的名称
        @wraps(func)
        def wrapper(*args, **kwargs):
            try:
                func_result = func(*args, **kwargs)
                print('    @%s passed!' % str(func.__name__), end='\n')
                return func_result
            except Exception as e:
                nowtime = time.strftime("%Y-%m-%d_%H-%M-%S")
                self.driver.get_screenshot_as_file(r'C:\Downloads\%s.png' % str(func.__name__ + '_' + nowtime))
                print('    @%s failed: %s' % (str(func.__name__), str(e)), end='\n')
                # 这里需要抛出异常，否则unittest检测不到异常，会认为case执行通过
                raise e
        return wrapper

browser = webdriver.Chrome(r"C:\Program Files (x86)\Google\Chrome\Application\chromedriver.exe")
Screen(browser, )

class TestFixtures(unittest.TestCase):

    # 定义类属性
    browser = webdriver.Chrome(r"C:\Program Files (x86)\Google\Chrome\Application\chromedriver.exe")

    # TestCase类中已经定义了实例属性_testMethodName，不需要自己去取，真是fuck，以后遇到问题先去看源码，别他妈自己瞎搞
    # @property
    # def __name__(self):
    #     return inspect.stack()[1][3]

    # 根据不同的参数调用不同的断言方法
    def assertration(self, assert_type, *args):
        assert_dict = {
            "assertTrue": self.assertTrue,
            "assertFalse": self.assertFalse,
            "assertEqual": self.assertEqual
        }
        try:
            assert_result = assert_dict[assert_type](*args)
            return assert_result
        except Exception as e:
            print(e, end='\n')
            # 这里需要抛出异常，否则unittest检测不到异常，会认为case执行通过
            raise e

    @classmethod
    def setUpClass(cls):
        print('******************** Start to test Class "%s" ********************' % str(cls.__name__), end='\n')
        cls.browser.implicitly_wait(5)
        cls.browser.maximize_window()
        cls.browser.get("https://www.baidu.com")

    @classmethod
    def tearDownClass(cls):
        print('\n')
        cls.browser.implicitly_wait(0)

    def setUp(self):
        print('<-------- Start to test Case "%s" -------->' % str(self._testMethodName))
        self.browser.refresh()

    def tearDown(self):
        pass


class TestCasesP0(TestFixtures):
    """百度搜索测试"""

    # 父类的类属性可以被子类和子类的实例直接引用，但是在定义子类时却无法直接引用父类的类属性，所以需要指向一个新的属于子类的变量（属性）
    browser = TestFixtures.browser

    @unittest.skip("skip")
    @Screen(browser)
    def test_search_01(self):
        """期望执行成功"""
        self.browser.find_element_by_id("kw").send_keys("Python3")
        self.browser.find_element_by_id("kw").submit()
        search_results = self.browser.find_elements_by_css_selector('.result.c-container em')
        for result in search_results:
            self.assertTrue('Python' == result.text or 'Python 3' == result.text or 'Python3' == result.text or
                            'python' == result.text or 'python 3' == result.text or 'python3' == result.text)

    @unittest.skip("skip")
    @Screen(browser)
    def test_search_02(self):
        """期望执行失败：参数类型不正确"""
        self.browser.find_element_by_id("kw").send_keys([1])
        self.browser.find_element_by_id("kw").submit()
        search_results = self.browser.find_elements_by_css_selector('.result.c-container em')
        for result in search_results:
            self.assertTrue('123' == result.text)


class TestCasesP1(TestFixtures):
    """百度搜索测试"""

    # 父类的类属性可以被子类和子类的实例直接引用，但是在定义子类时却无法直接引用父类的类属性，所以需要指向一个新的属于子类的变量（属性）
    browser = TestFixtures.browser

    @unittest.skip("skip")
    @Screen(browser)
    def test_search_01(self):
        """期望执行失败：和断言结果不符"""
        self.browser.find_element_by_id("kw").send_keys("haha")
        self.browser.find_element_by_id("kw").submit()
        search_results = self.browser.find_elements_by_css_selector('.result.c-container em')
        for result in search_results:
            self.assertration("assertFalse", 'Python3' == result.text or 'python3' == result.text)

    @unittest.skip("skip")
    @Screen(browser)
    def test_search_02(self):
        """期望执行失败：找不到元素"""
        self.browser.find_element_by_id("kw123").send_keys("123")
        self.browser.find_element_by_id("kw").submit()
        search_results = self.browser.find_elements_by_css_selector('.result.c-container em')
        for result in search_results:
            self.assertration("assertEqual", '123', result.text)

    @Screen(browser)
    def test_search_03(self):
        """期望执行失败：调用不可用的断言方法"""
        self.browser.find_element_by_id("kw").send_keys("123")
        self.browser.find_element_by_id("kw").submit()
        self.browser.find_elements_by_css_selector('.result.c-container em')
        self.assertration("assertTrue1", 1 == 1)

    @Screen(browser)
    def test_search_04(self):
        """期望执行成功"""
        self.browser.find_element_by_id("kw").send_keys("Python3")
        self.browser.find_element_by_id("kw").submit()
        self.browser.find_elements_by_css_selector('.result.c-container em')
        self.assertration("assertTrue", 1 == 1)

if __name__ == '__main__':
    suite = unittest.TestSuite()
    suite.addTest(TestCasesP0("test_search_01"))
    suite.addTest(TestCasesP0("test_search_02"))
    suite.addTest(TestCasesP1("test_search_01"))
    suite.addTest(TestCasesP1("test_search_02"))
    suite.addTest(TestCasesP1("test_search_03"))

    now_time = time.strftime("%Y-%m-%d_%H-%M-%S")
    report_name = r"C:\Downloads\TestResult_" + now_time + ".html"
    fp = open(report_name, 'wb')
    runner = HTMLTestReport.HTMLTestRunner(stream=fp, title='百度搜索测试报告', description='用例执行情况：', tester='alpha')
    # runner2 = HTMLTestRunner.HTMLTestRunner(stream=fp, title='百度搜索测试报告', description='用例执行情况：')
    runner.run(suite)
    fp.close()

    TestFixtures.browser.quit()
